package com.cloud.crashdemo.crash;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Environment;
import android.os.Process;
import android.util.Log;

import androidx.annotation.NonNull;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @auth: njb
 * @date: 2024/11/18 22:22
 * @desc: 描述
 */
public class CrashHandler implements Thread.UncaughtExceptionHandler {
    private static final String TAG = "CrashHandler";
    private static final boolean DEBUG = true;
    private static final String PATH = Environment.getExternalStorageDirectory().getPath() + "/crash/log/";
    private static final String FILE_NAME = "crash";
    private static final String FILE_NAME_SUFFIX = ".trace";
    @SuppressLint("StaticFieldLeak")
    private static volatile CrashHandler mInstance;
    private Thread.UncaughtExceptionHandler mDefaultCrashHandler;
    private Context mContext;
    private CrashHandler(){

    }

    public static CrashHandler getInstance(){
        if(mInstance == null){
            synchronized (CrashHandler.class){
                mInstance = new CrashHandler();
            }
        }
        return mInstance;
    }
    public void init(Context context){
        mDefaultCrashHandler = Thread.getDefaultUncaughtExceptionHandler();
        Thread.setDefaultUncaughtExceptionHandler(this);
        mContext = context.getApplicationContext();
    }

    @Override
    public void uncaughtException(@NonNull Thread thread, @NonNull Throwable ex) {
        try {
            dumpExceptionToSDCard(ex);
            upLoadExceptionToServer(ex);
        }catch (IOException e){
            e.printStackTrace();
        }
        ex.printStackTrace();
        if(mDefaultCrashHandler != null){
            mDefaultCrashHandler.uncaughtException(thread,ex);
        }else {
            Process.killProcess(Process.myPid());
        }
    }



    private void dumpExceptionToSDCard(Throwable ex) throws IOException {
        if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
            if(DEBUG){
                Log.w(TAG,"sdcard unmounted,skip dump exception");
                return;
            }
        }
        File dir = new File(PATH);
        if(!dir.exists()){
            dir.mkdirs();
        }
        long current = System.currentTimeMillis();
        String time = new SimpleDateFormat("yyyy-MM-dd- HH:mm:ss").format(new Date(current));
        File file = new File(PATH + FILE_NAME + time + FILE_NAME_SUFFIX);
        try{
            PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(file)));
            pw.println(time);
            dumpPhoneInfo(pw);
            pw.println();
            ex.printStackTrace(pw);
            pw.close();
        }catch (Exception e){
            Log.e(TAG,"dump crash info failed");
        }
    }

    private void dumpPhoneInfo(PrintWriter pw) throws PackageManager.NameNotFoundException {
        PackageManager pm = mContext.getPackageManager();
        PackageInfo pi = pm.getPackageInfo(mContext.getPackageName(),PackageManager.GET_ACTIVITIES);
        pw.println("App version: ");
        pw.println(pi.versionName);
        pw.println('_');
        pw.println(pi.versionCode);

        pw.println("OS version：");
        pw.println(Build.VERSION.RELEASE);
        pw.println('_');
        pw.println(Build.VERSION.SDK_INT);

        pw.println("Vendor：");
        pw.println(Build.MANUFACTURER);

        pw.println("Model：");
        pw.println(Build.MODEL);

        pw.println("CPU ABI：");
        pw.println(Build.CPU_ABI);
    }

    private void upLoadExceptionToServer(Throwable ex) throws IOException{
        //上传文件到服务器
    }
}
